#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"

#include "BList.h"

#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"



FTKBase::FTKBase(Ontology *o)
{
} /* FTKBase::FTKBase */ 



FTKBase::FTKBase(FILE *fp,Ontology *o)
{
	load(fp,o);
} /* FTKBase::FTKBase */ 


void FTKBase::create_boolean_objects(Ontology *o)
{
	AddFT(new FeatureTerm("true",o->get_sort("boolean"),0));
	AddFT(new FeatureTerm("false",o->get_sort("boolean"),0));
} /* FTKBase::create_boolean_objects */ 



FTKBase::~FTKBase()
{
	KBSortIndex *si;
	KBNameIndex *ni;

	while(!used_bases.EmptyP()) used_bases.ExtractIni();

	while(!sort_index.EmptyP()) {
		si=sort_index.ExtractIni();
		while(!si->fterms.EmptyP()) si->fterms.ExtractIni();
		delete si;
	} /* while */ 

	while(!name_index.EmptyP()) {
		ni=name_index.ExtractIni();
		while(!ni->fterms.EmptyP()) ni->fterms.ExtractIni();
		delete ni->name;
		delete ni;
	} /* while */ 

	while(!undefined_terms.EmptyP()) undefined_terms.ExtractIni();

} /* FTKBase::~FTKBase */ 


void FTKBase::Delete()
{
	KBSortIndex *si;
	KBNameIndex *ni;

	while(!sort_index.EmptyP()) {
		si=sort_index.ExtractIni();
		while(!si->fterms.EmptyP()) si->fterms.ExtractIni();
		delete si;
	} /* while */ 

	while(!name_index.EmptyP()) {
		ni=name_index.ExtractIni();
		while(!ni->fterms.EmptyP()) ni->fterms.ExtractIni();
		delete ni->name;
		delete ni;
	} /* while */ 

	while(!undefined_terms.EmptyP()) undefined_terms.ExtractIni();

	index.Delete();
} /* FTKBase::Delete */ 



bool FTKBase::save(FILE *fp,FTKBase *domain_model)
{
	List<FeatureTerm> l;
	FeatureTerm *f;
	FeatureTerm *f_set=FeatureTerm::SetFeatureTerm();
	char *s;

	l.Instance(index);
	l.Rewind();
	while(l.Iterate(f)) {
		f_set->addSetValue(new FeatureTerm(f));
	} // while 
	s=f_set->toStringNOOS(domain_model);
	fprintf(fp,"%s\n",s);
	delete []s;
	delete f_set;

	return true;
} /* FTKBase::save */ 


bool FTKBase::load(FILE *fp,Ontology *o)
{
	FeatureTerm *f_set,*f;
	List<FeatureTerm> *l;

	f_set=FeatureTerm::fromFileNOOS(fp,this,o);

	l=f_set->set_values_quick();

	l->Rewind();
	while(l->Iterate(f)) {
		AddFT(f);
	} // while 
	l=0;
	delete f_set;
	return true;
} /* FTKBase::load */ 


KBNameIndex *FTKBase::SearchName(Symbol *name)
{
	List<KBNameIndex> l;
	KBNameIndex *ni;

	l.Instance(name_index);
	l.Rewind();
	while(l.Iterate(ni)) {
		if (name==0) {
			if (ni->name==0) return ni;
		} else {
			if (ni->name!=0 && ni->name->cmp(name)) return ni;
		} /* if */ 
	} /* while */ 

	return 0;
} /* FTKBase::SearchName */ 


FeatureTerm *FTKBase::SearchUndefinedFT(Symbol *name)
{
	List<FeatureTerm> *l;
	FeatureTerm *found=0;
	FeatureTerm *f=0;

	l=SearchFT(name);

	l->Rewind();
	while(l->Iterate(f) && found==0) {
		if (undefined_terms.MemberRefP(f)) {
			found=f;
		} /* if */  
	} /* while */ 
	while(!l->EmptyP()) l->ExtractIni();
	delete l;

	return found;
} /* FTKBase::SearchUndefinedFT */ 


KBSortIndex *FTKBase::SearchSort(Sort *sort)
{
	List<KBSortIndex> l;
	KBSortIndex *si;

	l.Instance(sort_index);
	l.Rewind();
	while(l.Iterate(si)) {
		if (sort==si->s) return si;
	} /* while */ 

	return 0;
} /* FTKBase::SearchSort */ 


void FTKBase::AddFT(FeatureTerm *f)
{
	KBNameIndex *ni;
	KBSortIndex *si;

//	if (f->getName!=0) printf("Adding %s\n",f->getName()->get());

	index.Add(f);
	
	ni=SearchName(f->getName());
	if (ni!=0) {
		ni->fterms.Add(f);
	} else {
		ni=new KBNameIndex();
		if (f->getName()!=0) {
			ni->name=new Symbol(f->getName());
		} else {
			ni->name=0;
		} /* if */ 
		ni->fterms.Add(f);
		name_index.Add(ni);
	} /* if */ 

	si=SearchSort(f->getSort());
	if (si!=0) {
		si->fterms.Add(f);
	} else {
		si=new KBSortIndex();
		si->s=f->getSort();
		si->fterms.Add(f);
		sort_index.Add(si);
	} /* if */ 

} /* FTKBase::AddFT */ 


void FTKBase::AddUndefinedFT(FeatureTerm *f)
{
	AddFT(f);

	undefined_terms.Add(f);
} /* FTKBase::AddFT */ 



void FTKBase::DeleteFT(FeatureTerm *f)
{
	KBNameIndex *ni;
	KBSortIndex *si;

	ni=SearchName(f->getName());
	si=SearchSort(f->getSort());

	if (ni!=0) {
		ni->fterms.DeleteElement(f);
		if (ni->fterms.EmptyP()) {
			name_index.DeleteElement(ni);
			delete ni->name;
			delete ni;
		} /* if */ 
	} /* if */ 

	if (si!=0) {
		si->fterms.DeleteElement(f);
		if (si->fterms.EmptyP()) {
			sort_index.DeleteElement(si);
			delete si;
		} /* if */ 
	} /* if */ 

	index.DeleteElement(f);
	undefined_terms.DeleteElement(f);
} /* FTKBase::DeleteFT */ 


List<FeatureTerm> *FTKBase::SearchFT(Symbol *name)
{
	List<FeatureTerm> *l,l2;
	FeatureTerm *f;
	KBNameIndex *ni;

	l=new List<FeatureTerm>;

	ni=SearchName(name);

	if (ni!=0) {
		l2.Instance(ni->fterms);
		l2.Rewind();
		while(l2.Iterate(f)) l->Add(f);
	} /* if */ 

	/* Search in the used memories: */ 
	{
		List<FTKBase> l2;
		FTKBase *b;
		List<FeatureTerm> *res;

		l2.Instance(used_bases);
		l2.Rewind();
		while(l2.Iterate(b)) {
			res=b->SearchFT(name);
			while(!res->EmptyP()) l->Add(res->ExtractIni());
			delete res;
		} /* while */ 
	}

	return l;
} /* FTKBase::SearchFT */ 


List<FeatureTerm> *FTKBase::SearchFT(Sort *s)
{
	List<FeatureTerm> *l,l2;
	FeatureTerm *f;

	l=new List<FeatureTerm>;

	{
		List<KBSortIndex> l3;
		KBSortIndex *si;

		l3.Instance(sort_index);
		l3.Rewind();
		while(l3.Iterate(si)) {
			if (s==0 || s->isSubsort(si->s)) {
				l2.Instance(si->fterms);
				l2.Rewind();
				while(l2.Iterate(f)) l->Add(f);
			} /* if */ 
		} /* while */ 
	}

	/* Search in the used memories: */ 
	{
		List<FTKBase> l2;
		FTKBase *b;
		List<FeatureTerm> *res;

		l2.Instance(used_bases);
		l2.Rewind();
		while(l2.Iterate(b)) {
			res=b->SearchFT(s);
			while(!res->EmptyP()) l->Add(res->ExtractIni());
			delete res;
		} /* while */ 
	}	

	return l;
} /* FTKBase::SearchFT */ 


List<FeatureTerm> *FTKBase::RetrieveFT(FeatureTerm *pattern)
{
	List<FeatureTerm> *l,l2;
	FeatureTerm *f;
	Sort *s;

	s=pattern->getSort();

	l=new List<FeatureTerm>;

	{
		List<KBSortIndex> l3;
		KBSortIndex *si;

		l3.Instance(sort_index);
		l3.Rewind();
		while(l3.Iterate(si)) {
			if (s->isSubsort(si->s)) {
				l2.Instance(si->fterms);
				l2.Rewind();
				while(l2.Iterate(f)) {
					if (pattern->subsumes(f)) l->Add(f);
				} /* if */ 
			} /* if */ 
		} /* while */ 
	}	

	/* Search in the used memories: */ 
	{
		List<FTKBase> l2;
		FTKBase *b;
		List<FeatureTerm> *res;

		l2.Instance(used_bases);
		l2.Rewind();
		while(l2.Iterate(b)) {
			res=b->RetrieveFT(pattern);
			while(!res->EmptyP()) l->Add(res->ExtractIni());
			delete res;
		} /* while */ 
	}

	return l;
} /* FTKBase::RetrieveFT */ 


List<FeatureTerm> *FTKBase::LocalSearchFT(Symbol *name)
{
	List<FeatureTerm> *l,l2;
	FeatureTerm *f;
	KBNameIndex *ni;

	l=new List<FeatureTerm>;

	ni=SearchName(name);

	if (ni!=0) {
		l2.Instance(ni->fterms);
		l2.Rewind();
		while(l2.Iterate(f)) l->Add(f);
	} /* if */ 

	return l;
} /* FTKBase::SearchFT */ 


List<FeatureTerm> *FTKBase::LocalSearchFT(Sort *s)
{
	List<FeatureTerm> *l,l2;
	FeatureTerm *f;

	l=new List<FeatureTerm>;

	{
		List<KBSortIndex> l3;
		KBSortIndex *si;

		l3.Instance(sort_index);
		l3.Rewind();
		while(l3.Iterate(si)) {
			if (s==0 || s->isSubsort(si->s)) {
				l2.Instance(si->fterms);
				l2.Rewind();
				while(l2.Iterate(f)) l->Add(f);
			} /* if */ 
		} /* while */ 
	}

	return l;
} /* FTKBase::SearchFT */ 


List<FeatureTerm> *FTKBase::LocalRetrieveFT(FeatureTerm *pattern)
{
	List<FeatureTerm> *l,l2;
	FeatureTerm *f;
	Sort *s;

	s=pattern->getSort();

	l=new List<FeatureTerm>;

	{
		List<KBSortIndex> l3;
		KBSortIndex *si;

		l3.Instance(sort_index);
		l3.Rewind();
		while(l3.Iterate(si)) {
			if (s->isSubsort(si->s)) {
				l2.Instance(si->fterms);
				l2.Rewind();
				while(l2.Iterate(f)) {
					if (pattern->subsumes(f)) l->Add(f);
				} /* if */ 
			} /* if */ 
		} /* while */ 
	}	

	return l;
} /* FTKBase::RetrieveFT */ 


bool FTKBase::ImportNOOS(char *filename,Ontology *o)
{
	bool retval=false;
	FILE *fp;

	fp=fopen(filename,"rb+");
	if (fp!=0) {
		retval=ImportNOOS(fp,o);
		fclose(fp);
	} /* if */ 

	return retval;
} /* FTKBase::ImportNOOS */ 



bool FTKBase::ImportNOOS(FILE *fp,Ontology *o)
{
	char *token=0;
	bool end;
	int type;
	int state=0;
	long pos=0,lastpos=0;

	end=false;
	pos=ftell(fp);	
	do{
		delete []token;
		lastpos=ftell(fp);	
		token=FeatureTerm::getTokenNOOS(fp,&type);

		if (token!=0) {
			switch(state) {
			case 0: if (type==TOKEN_LEFT_PAR) {
						state=1;
						pos=lastpos;
					} else {
						end=true;
					} // if
					break;

			case 1: if (type==TOKEN_SYMBOL) {
						if (strcmp(token,"define-ontology")==0) state=2;
						if (strcmp(token,"define-sort")==0) state=3;
						if (strcmp(token,"define-domain-model")==0) state=4;
						if (strcmp(token,"define")==0 ||
							strcmp(token,"define-episode")==0) {
							fseek(fp,pos,SEEK_SET);
							FeatureTerm *f=FeatureTerm::fromFileNOOS(fp,this,o);
							if (f!=0) {
//								printf("term added %s\n",(f->getName()!=0 ? f->getName()->get() : "?"));
								AddFT(f);
								state=0;
							} else {
								end=true;
							} /* if */ 
						} /* if */ 
						if (state==1) end=true;
					} else {
						end=true;
					} /* if */ 
					break;

			case 2: /* define-ontology: */ 
					if (type==TOKEN_SYMBOL) {
						int npar=1;
						Symbol *s;

						s=new Symbol(token);
						o->new_sort(s,o->get_sort("any"),0);
						delete s;

						while(npar!=0 && !end) {
							delete []token;
							token=FeatureTerm::getTokenNOOS(fp,&type);
							if (token==0) end=true;
							if (type==TOKEN_LEFT_PAR) npar++;
							if (type==TOKEN_RIGHT_PAR) npar--;
						} /* while */ 
						state=0;
					} else {
						end=true;
					} /* if */ 
					break;

			case 3: /* define-sort: */ 
					{
						bool first=true;
						Symbol *name=0,*super=0;
						FeatureTerm *default_value;
						List<Symbol> fnames;
						List<Symbol> fsorts;
						List<FeatureTerm> fdefault;
						List<bool> fsingleton;

						while(state==3 && !end) {
							if (type==TOKEN_LEFT_PAR) {
								if (first) {
									delete []token;
									token=FeatureTerm::getTokenNOOS(fp,&type);

									if (token==0 || type!=TOKEN_SYMBOL) {
										end=true;							
									} else {
										super=new Symbol(token);

										delete []token;
										token=FeatureTerm::getTokenNOOS(fp,&type);
										if (token==0 || type!=TOKEN_SYMBOL) {
											end=true;
										} else {
											name=new Symbol(token);
											delete []token;
											token=FeatureTerm::getTokenNOOS(fp,&type);
											if (type!=1) end=true;
											first=false;
										} /* if */ 
									} /* if */ 
								} else {
									delete []token;
									token=FeatureTerm::getTokenNOOS(fp,&type);
									if (token==0 || type!=TOKEN_SYMBOL) {
										end=true;							
									} else {
										bool singleton=false;
										fnames.Add(new Symbol(token));

										delete []token;
										token=FeatureTerm::getTokenNOOS(fp,&type);

										if (type==TOKEN_SINGLETON) {
											singleton=true;
											delete []token;
											token=FeatureTerm::getTokenNOOS(fp,&type);
										} // if 

										if (token==0 || type!=TOKEN_SYMBOL) {
											end=true;
										} else {
											long pos2=0;
											fsorts.Add(new Symbol(token));
											delete []token;
											pos2=ftell(fp);
											token=FeatureTerm::getTokenNOOS(fp,&type);
											if (type==TOKEN_RIGHT_PAR) {
												fdefault.Add(0);
											} else {
												fseek(fp,pos2,SEEK_SET);
												default_value=FeatureTerm::fromFileNOOS(fp,this,o);
												if (default_value!=0) {
													fdefault.Add(default_value);
													token=FeatureTerm::getTokenNOOS(fp,&type);
													if (type!=TOKEN_RIGHT_PAR) end=true;
												} else {
													end=true;
												} // if 
											} // if 
											fsingleton.Add(new bool(singleton));
										} /* if */ 
									} /* if */ 

								} /* if */ 
							} else if (type==1) {
								/* Create the sort with the corresponding features: */ 
								Sort *s=o->new_sort(name,o->get_sort(super),0);
								Symbol *s1,*s2;
								bool *singleton;

								while(!fnames.EmptyP()) {
									s1=fnames.ExtractIni();
									s2=fsorts.ExtractIni();
									default_value=fdefault.ExtractIni();
									singleton=fsingleton.ExtractIni();
									s->addFeature(s1,o->get_sort(s2),default_value,*singleton);
									delete s1;
									delete s2;
									delete singleton;
								} /* whiel */ 

								delete name;
								delete super;
								state=0;							
							} else {
								delete name;
								delete super;
								end=true;
							} /* if */ 	
							
							if (!end && state==3) {
								delete []token;
								token=FeatureTerm::getTokenNOOS(fp,&type);
								if (token==0) end=true;
							} /* if */ 
						} /* while */ 
					}
					break;

			case 4: /* define-domain-model: */ 
					if (type==2) {
						int npar=1;
						while(npar!=0 && !end) {
							delete []token;
							token=FeatureTerm::getTokenNOOS(fp,&type);
							if (token==0) end=true;
							if (type==0) npar++;
							if (type==1) npar--;
						} /* while */ 
						state=0;
					} else {
						end=true;
					} /* if */ 
					break;

			} /* switch */ 
			delete []token;
			token=0;
		} else {
			end=true;
		} /* if */ 
	}while(!end);
	delete []token;
	return true;
} /* FTKBase::ImportNOOS */ 



int FTKBase::get_n_undefined_terms(void)
{
	return undefined_terms.Length();
} /* FTKBase::get_n_undefined_terms */ 



bool FTKBase::MemberP(FeatureTerm *f)
{
	bool found=false;
	List<FeatureTerm> *l;
	if (f->getName()!=0) {
		l=SearchFT(f->getName());
		while(!l->EmptyP()) {
			if (*(l->ExtractIni())==*(f)) found=true;
		} /* if */ 
		while(!l->EmptyP()) l->ExtractIni();
		delete l;
	} else {
		l=SearchFT(f->getSort());
		while(!l->EmptyP()) {
			if (*(l->ExtractIni())==*(f)) found=true;
		} /* if */ 
		while(!l->EmptyP()) l->ExtractIni();
		delete l;
	} /* if */ 

	return found;
} /* FTKBase::memberP */ 



bool FTKBase::MemberP(FeatureTermContainer *ft)
{
	bool found=false;
	List<FeatureTerm> *l;
	if (ft->m_name!=0) {
		l=SearchFT(ft->m_name);
		while(!l->EmptyP()) {
			if (l->ExtractIni()->m_ft==ft) found=true;
		} /* if */ 
		while(!l->EmptyP()) l->ExtractIni();
		delete l;
	} else {
		l=SearchFT(ft->m_sort);
		while(!l->EmptyP()) {
			if (l->ExtractIni()->m_ft==ft) found=true;
		} /* if */ 
		while(!l->EmptyP()) l->ExtractIni();
		delete l;
	} /* if */ 

	return found;
} /* FTKBase::memberP */ 


void FTKBase::uses(FTKBase *base)
{
	used_bases.Add(base);
} /* FTKBase::uses */ 


void FTKBase::print_undefined_terms(void)
{
	List<FeatureTerm> l;
	FeatureTerm *f;
	char *s;

	l.Instance(undefined_terms);
	while(l.Iterate(f)) {
		s=f->toStringNOOS();
		printf("%s\n",s);
		fflush(0);
		delete []s;
	} /* while */ 
} /* FTKBase::print_undefined_terms */ 


int FTKBase::get_n_terms(void)
{
	return index.Length();
} /* FTKBase::get_n_terms */ 

